
#!/usr/bin/python
# -*- coding: utf-8 -*-

import pc
from pc import *

import sexprs
    
####################################################################################
#################################Parsers############################################
####################################################################################
    
ps = ParserStack()

#pSexpr
ps.parser(delayed(lambda : pSkip))
ps.parser(delayed(lambda : pBoolean))
ps.parser(delayed(lambda : pNumber))
ps.parser(delayed(lambda : pSymbol))
ps.parser(delayed(lambda : pString))
ps.parser(delayed(lambda : pChar))
ps.parser(delayed(lambda : pNil))
ps.parser(delayed(lambda : pPair))
ps.parser(delayed(lambda : pVector))
ps.parser(delayed(lambda : pQuote))
ps.disjs(9)
ps.parser(delayed(lambda : pSkip))
ps.catens(3)
ps.pack(lambda x: x[1])
pSexpr = ps.done()
#pSexpr


#Get parser and return the same parser with braces
def bracesParser(pc,packer = lambda x : x):
    ps1 = ParserStack()
    ps1.parser(pcChar("("))
    ps1.parser(pc)
    ps1.parser(pcChar(")"))
    ps1.catens(3)
    ps1.parser(pcChar("["))
    ps1.parser(pc)
    ps1.parser(pcChar("]"))
    ps1.catens(3)
    ps1.disjs(2)
    ps1.pack(lambda x : packer(x[1]))
    retParser = commentsParser(ps1.done())
    return retParser
#bracesParser

#pWhitespace
ps.parser(const(lambda c: c <= ' '))
ps.pack(lambda m: '')
pWhitespace = ps.done()
#pWhitespace

#pLineComment
ps.parser(pcChar(';'))
ps.parser(butNot(const(),pcChar('\n')))
ps.star()
ps.parser(pcChar('\n'))
ps.catens(3)
ps.pack(lambda m: '')
pLineComment = ps.done()
#pLineComment

#pSexprComment
ps.parser(pcChar('#'))
ps.parser(pcChar(';'))
ps.parser(pSexpr)
ps.catens(3)
ps.pack(lambda m: '')
pSexprComment = ps.done()
#pSexprComment

#pSkip
ps.parser(pWhitespace)
ps.parser(pLineComment)
ps.parser(pSexprComment)
ps.disjs(3)
ps.star()
ps.pack(lambda m: '')
pSkip = ps.done()
#pSkip

#pFalse
ps.parser(pcWordCI("#f"))
ps.pack(lambda x : sexprs.Boolean(False))
pFalse = ps.done()
#pFalse

#pTrue
ps.parser(pcWordCI("#t"))
ps.pack(lambda x : sexprs.Boolean(True))
pTrue = ps.done()
#pTrue

#pBoolean
ps.parser(pTrue)
ps.parser(pFalse)
ps.disjs(2)
pBoolean = ps.done()
#pBoolean

#pNat
ps.parser(pcRange("0","9"))
ps.plus()
ps.pack(lambda x : int(''.join(x)))
pNat = ps.done()
#pNat

#pHexDigit
ps.parser(pcRange("0","9"))
ps.parser(pcRange("a","f"))
ps.parser(pcRange("A","F"))
ps.disjs(3)
pHexDigit = ps.done()
#pHexDigit

#pHex
ps.parser(pcChar('0'))
ps.parser(pcOneOfCI('xh'))
ps.parser(pHexDigit)
ps.plus()
ps.catens(3)
ps.pack(lambda x : int('0x' + ''.join(x[2]), 16))
pHex = ps.done()
#pHex

#pUnsigned
ps.parser(pHex)
ps.parser(pNat)
ps.disjs(2)
ps.pack(lambda x : x)
pUnsigned = ps.done()
#pUnsigned

#pSigned
ps.parser(pcChar('-'))
ps.parser(pUnsigned)
ps.catens(2)
ps.pack(lambda x : (-1)*x[1])
ps.parser(pcChar('+'))
ps.parser(pUnsigned)
ps.catens(2)
ps.pack(lambda x : x[1])
ps.disjs(2)
pSigned = ps.done()
#pSigned

#pInt
ps.parser(pSigned)
ps.parser(pUnsigned)
ps.disjs(2)
ps.pack(lambda x : sexprs.Integer(x))
pInt = ps.done()
#pInt

#pZero
ps.parser(pcChar('0'))
ps.plus()
pZero = ps.done()
ps.parser(pcChar('0'))
ps.parser(pcOneOfCI('xh'))
ps.parser(pZero)
ps.plus()
ps.catens(3)
ps.parser(pZero)
ps.disjs(2)
ps.pack(lambda x : 0)
pZero = ps.done()
#pZero

#pFraction
ps.parser(pInt)
ps.parser(pcChar('/'))
ps.parser(butNot(pNat,pZero))
ps.catens(3)
ps.pack(lambda x : sexprs.Fraction(x[0].val/x[2]))
pFraction = ps.done()
#pFraction

#pNumber
ps.parser(pFraction)
ps.parser(pInt)
ps.disjs(2)
pNumber = ps.done()
#pNumber


pBigLetter = pc.const ( lambda x : (x >= "A" and x <= "Z") )
pSmallLetter = pc.const ( lambda x : (x >= "a" and x <= "z"))
pPunctuation = pc.pcOneOf('!$^*-_=+<>/?')

#pSymbol
ps.parser(pBigLetter)
ps.parser(pSmallLetter)
ps.parser(pPunctuation)
ps.parser(pcRange("0","9"))
ps.disjs(4)
ps.plus()
ps.pack(lambda x : sexprs.Symbol(''.join(x).upper()))
pSymbol = ps.done()
#pSymbol


pNewline = pack(caten(pcChar('\\'),pcChar('n')),lambda x: '\n')
pReturn = pack(caten(pcChar('\\'),pcChar('r')),lambda x: '\r')
pTab = pack(caten(pcChar('\\'),pcChar('t')),lambda x: '\t')
pFormfeed = pack(caten(pcChar('\\'),pcChar('f')),lambda x: '\f')
pBackslash = pack(caten(pcChar('\\'),pcChar('\\')),lambda x: '\\')
pDoubleQuate = pack(caten(pcChar('\\'),pcChar(chr(34))),lambda x: chr(34)) #\"
pLambda = pack(caten(pcChar('\\'),pcChar('l')),lambda x: chr(0x03bb))

#pString
ps.parser(pcChar('"'))
ps.parser(butNot(const(),disj(pcChar(chr(92)),pcChar(chr(34)))))
ps.parser(disjs(pNewline,pReturn,pTab,pFormfeed,pBackslash,pBackslash,pDoubleQuate,pLambda))
ps.disjs(2)
ps.star()
ps.parser(pcChar('"'))
ps.catens(3)
ps.pack(lambda x : sexprs.String(''.join(x[1])))
pString = ps.done()
#pString

#Char
pCharNewline = pack(caten(pcWord('#\\'),pcWordCI('newline')),lambda x: chr(10)) #\n
pCharReturn = pack(caten(pcWord('#\\'),pcWordCI('return')),lambda x: chr(13))   #\r
pCharTab = pack(caten(pcWord('#\\'),pcWordCI('tab')),lambda x: chr(9))          #\t
pCharFormfeed = pack(caten(pcWord('#\\'),pcWordCI('page')),lambda x: chr(12))   #\f
pCharLambda = pack(caten(pcWord('#\\'),pcWordCI('lambda')),lambda x: chr(0x03bb))

pCharHex = pack(caten(pcWord('#\\x'),plus(pHexDigit)),lambda x: chr(int('0x' + ''.join(x[1]), 16)))

pCharAsIs = pack(caten(pcWord('#\\'),const()),lambda x: x[1])
ps.parser(disjs(pCharNewline,pCharReturn,pCharTab,pCharTab,pCharFormfeed,pCharLambda,pCharHex,pCharAsIs))
ps.pack(lambda x : sexprs.Char(x))
pChar = ps.done()
#Char

#pNil
ps.parser(pcChar('('))
ps.parser(pWhitespace)
ps.star()
ps.parser(pcChar(')'))
ps.catens(3)
ps.pack(lambda x : sexprs.Nil())
pNil = ps.done()
#pNil

def pairBuilder(s,a):
    if(s):
        return sexprs.Pair(s[0],pairBuilder(s[1:],a))
    else:
        return a
    return

#pPairProper
ps.parser(pcChar('('))
ps.parser(pSexpr)
ps.star()
ps.parser(pcChar(')'))
ps.catens(3)
ps.pack(lambda x : pairBuilder(x[1],sexprs.Nil()))
pPairProper = ps.done()
#pPairProper

#pPairImproper
ps.parser(pcChar('('))
ps.parser(pSexpr)
ps.plus()
ps.parser(pcChar('.'))
ps.parser(pSexpr)
ps.parser(pcChar(')'))
ps.catens(5)
ps.pack(lambda x : pairBuilder(x[1],x[3]))
pPairImproper = ps.done()
#pPairImproper

#pPair
ps.parser(pPairProper)
ps.parser(pPairImproper)
ps.disjs(2)
pPair = ps.done()
#pPair

#pVector
ps.parser(pcChar('#'))
ps.parser(pcChar('('))
ps.parser(pSexpr)
ps.star()
ps.parser(pcChar(')'))
ps.catens(4)
ps.pack(lambda x : sexprs.Vector(x[2]))
pVector = ps.done()
#pVector

#pQuote
pQuoted = pack(caten(pcChar(chr(39)),pSexpr),lambda x: sexprs.Pair(sexprs.Symbol('quote'), sexprs.Pair(x[1], sexprs.Nil())))
pQQuoted = pack(caten(pcChar(chr(96)),pSexpr),lambda x: sexprs.Pair(sexprs.Symbol('quasiquote'), sexprs.Pair(x[1], sexprs.Nil())))
pUnquotedSpliced = pack(caten(pcWord(',@'),pSexpr),lambda x: sexprs.Pair(sexprs.Symbol('unquote-splicing'), sexprs.Pair(x[1], sexprs.Nil())))
pUnquoted = pack(caten(pcChar(','),pSexpr),lambda x: sexprs.Pair(sexprs.Symbol('unquote'), sexprs.Pair(x[1], sexprs.Nil())))
pQuote = disjs(pQuoted,pQQuoted,pUnquotedSpliced,pUnquoted)
#pQuote

####################################################################################
#################################End of Parsers#####################################
####################################################################################




















